package com.hifar.test.report.render;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.config.GramerSymbol;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.policy.TextRenderPolicy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hifar.abi.utils.minio.MinioUtils;
import com.hifar.base.serialNo.service.IBaseSerialNoService;
import com.hifar.constant.SystemConsts;
import com.hifar.fw.utils.id.IdUtils;
import com.hifar.idm.util.ConvertPdfUtil;
import com.hifar.plat.baseModal.pojo.BaseOssFiles;
import com.hifar.plat.baseModal.service.IBaseOssFilesService;
import com.hifar.plugins.SignRenderPolicy;
import com.hifar.plugins.TextBlankRenderPolicy;
import com.hifar.plugins.TimeRenderPolicy;
import com.hifar.sys.MinioUtil;
import com.hifar.test.entrust.constant.EntrustConsts;
import com.hifar.test.entrust.constant.ReportConsts;
import com.hifar.test.entrust.constant.TestConsts;
import com.hifar.test.entrust.pojo.HfEnvEntrust;
import com.hifar.test.entrust.pojo.HfEnvGkEntrust;
import com.hifar.test.entrust.pojo.HfEnvGkPiece;
import com.hifar.test.entrust.pojo.HfEnvPiece;
import com.hifar.test.entrust.service.IHfEnvEntrustService;
import com.hifar.test.entrust.service.IHfEnvGkEntrustService;
import com.hifar.test.entrust.service.IHfEnvGkPieceService;
import com.hifar.test.report.pojo.HfEnvReport;
import com.hifar.test.report.pojo.VO.ReportCreateVO;
import com.hifar.test.report.render.model.HfEnvTaskTestModel;
import com.hifar.test.report.service.IHfEnvReportService;
import com.hifar.test.task.pojo.HfEnvTask;
import com.hifar.test.task.service.IHfEnvTaskService;
import com.hifar.test.template.pojo.HfEnvTemplate;
import com.hifar.test.template.service.IHfEnvTemplateService;
import com.hifar.test.test.service.IHfEnvTestService;
import com.hifar.utils.ToolKit;
import org.apache.commons.io.FileUtils;
import org.ddr.poi.html.HtmlRenderPolicy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhuWeiWei
 * @description 环境报告渲染
 * @date 2025/1/10 15:38
 */
@Component
public class HfEnvReportRender {
    @Autowired
    private IHfEnvReportService reportService;
    @Autowired
    private IBaseSerialNoService baseSerialNoService;
    @Autowired
    private IHfEnvEntrustService envEntrustService;
    @Autowired
    private IHfEnvGkEntrustService gkEntrustService;
    @Autowired
    private IHfEnvTemplateService envTemplateService;
    @Autowired
    private IBaseOssFilesService baseOssFilesService;
    @Autowired
    private IHfEnvGkPieceService gkPieceService;
    @Autowired
    private IHfEnvTestService testService;
    @Autowired
    private IHfEnvTaskService taskService;


    public HfEnvReport renderReport(ReportCreateVO reportCreateVO) {
        HfEnvReport hfEnvReport = new HfEnvReport();
        String gkEntrustId = reportCreateVO.getEntrustId();
        String templateId = reportCreateVO.getTemplateId();
        List<String> testIdList = reportCreateVO.getTestIdList();
        hfEnvReport.setGkEntrustId(gkEntrustId);
        hfEnvReport.setTestIds(String.join(",", testIdList));
        hfEnvReport.setStatus(ReportConsts.REPORT_STATUS_ING);
        hfEnvReport.setQmPush(SystemConsts.NO);
        hfEnvReport.setPdmPush(SystemConsts.NO);
        HfEnvGkEntrust hfEnvGkEntrust = gkEntrustService.getById(gkEntrustId);
        Assert.notNull(hfEnvGkEntrust, "委托数据不存在!");
        String entrustCode = hfEnvGkEntrust.getEntrustCode();

        String reportCode = baseSerialNoService.getSerialNo(gkEntrustId + "Report", entrustCode + "-", "", 2);

        HfEnvTemplate reportTemplate = envTemplateService.getById(templateId);
        Assert.notNull(reportTemplate, "报告模板不存在!");
        String templatePath = reportTemplate.getTemplatePath();
        Assert.notNull(templatePath, "报告模板文件不存在!");
        File tempDirectory = FileUtils.getTempDirectory();
        String templateLocalPath = tempDirectory + File.separator + IdUtils.uuid32() + ".docx";
        String tempPdfPath = null;
        File tempWordFile = null;
        boolean isSuccess = false;
        try {
            String wordObjectName = "hifar/idm/" + reportCode + ".docx";
            String pdfObjectName = "hifar/idm/" + reportCode + ".pdf";
            MinioUtil.downloadFile(MinioUtil.PRE_DEFAULT, templatePath, templateLocalPath);
            Map<String, Object> pageData = this.packageData(hfEnvGkEntrust, testIdList, hfEnvReport);
            pageData.put("reportCode", reportCode);
            tempWordFile = this.render(new File(templateLocalPath), pageData);
            tempPdfPath = ConvertPdfUtil.wordToPdf(tempWordFile.getAbsolutePath());
            MinioUtils.uploadLocalFileToMinio(MinioUtil.PRE_DEFAULT, wordObjectName, tempWordFile.getAbsolutePath());
            MinioUtils.uploadLocalFileToMinio(MinioUtil.PRE_DEFAULT, pdfObjectName, tempPdfPath, "application/pdf");
            hfEnvReport.setWordPath(wordObjectName);
            hfEnvReport.setPdfPath(pdfObjectName);
            isSuccess = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (new File(templateLocalPath).exists()) {
                new File(templateLocalPath).delete();
            }
            if (Objects.nonNull(tempWordFile)) {
                tempWordFile.delete();
            }
            if (Objects.nonNull(tempPdfPath)) {
                new File(tempPdfPath).delete();
            }
        }
        hfEnvReport.setStatus(isSuccess ? ReportConsts.REPORT_STATUS_CG : ReportConsts.REPORT_STATUS_ERROR);
        hfEnvReport.setReportCode(reportCode);
        reportService.save(hfEnvReport);
        return hfEnvReport;
    }

    private File render(File templateFile, Map<String, Object> data) throws Exception {
        ConfigureBuilder builder = Configure.builder();

        File tempDirectory = FileUtils.getTempDirectory();

        String tempWordPath = tempDirectory + File.separator + IdUtils.uuid32() + ".docx";

        HtmlRenderPolicy htmlRenderPolicy = new HtmlRenderPolicy();
        // < 注册为表格渲染
        LoopRowTableRenderPolicy loopRowTableRenderPolicy = new LoopRowTableRenderPolicy();
        TimeRenderPolicy timeRenderPolicy = new TimeRenderPolicy("yyyy年MM月dd日", true);
        TimeRenderPolicy timeRenderPolicy2 = new TimeRenderPolicy("yyyy/MM/dd", true);
        SignRenderPolicy autographRenderPolicy = new SignRenderPolicy(60, 25);// 电子签名渲染
        SignRenderPolicy signatureRenderPolicy = new SignRenderPolicy(60, 60);// 电子签章渲染
        builder.addPlugin(':', timeRenderPolicy);
        builder.addPlugin('-', timeRenderPolicy2);
        builder.addPlugin('<', loopRowTableRenderPolicy);
        builder.addPlugin('$', autographRenderPolicy);
        builder.bind("testCondition", htmlRenderPolicy);
        builder.addPlugin(GramerSymbol.TEXT.getSymbol(), new TextBlankRenderPolicy(""));
        // 日期渲染插件配置
        Configure configure = builder.build();
        XWPFTemplate
                .compile(templateFile.getPath(), configure)
                .render(data)
                .writeAndClose(new FileOutputStream(tempWordPath));
        return new File(tempWordPath);
    }

    private Map<String, Object> packageData(HfEnvGkEntrust hfEnvGkEntrust, List<String> testIdList, HfEnvReport hfEnvReport) {
        Map<String, Object> dataMap = new HashMap<>(16);
        dataMap.put("entrustCode", hfEnvGkEntrust.getEntrustCode());
        dataMap.put("entrustCust", hfEnvGkEntrust.getEntrustCust());
        dataMap.put("entrustTime", hfEnvGkEntrust.getEntrustTime());
        dataMap.put("entrustUserName", hfEnvGkEntrust.getEntrustUserName());
        dataMap.put("entrustUserPhone", hfEnvGkEntrust.getEntrustUserPhone());
        String gkEntrustId = hfEnvGkEntrust.getId();
        List<HfEnvGkPiece> gkPieceList = gkPieceService.listByGkEntrustId(gkEntrustId);
        List<HfEnvTaskTestModel> taskTestModelList = testService.listRenderModelByIds(testIdList);
        Assert.notEmpty(taskTestModelList, "试验数据不存在!");
        List<String> taskIdList = taskTestModelList.stream()
                .map(HfEnvTaskTestModel::getTaskId)
                .collect(Collectors.toList());
        List<HfEnvTask> taskList = taskService.listByIds(taskIdList);
        // 最小试验开始时间
        Date testStartDate = null;
        // 最大试验结束时间
        Date testEndDate = null;
        // 最小温度
        BigDecimal minTemperature = null;
        // 最大温度
        BigDecimal maxTemperature = null;
        // 最小湿度
        BigDecimal minHumidity = null;
        // 最大湿度
        BigDecimal maxHumidity = null;

        Map<String, List<HfEnvTaskTestModel>> taskTestVOListGroup = new HashMap<>();

        List<String> testResultList = new ArrayList<>();
        List<String> processDescList = new ArrayList<>();

        for (HfEnvTaskTestModel taskTestModel : taskTestModelList) {
            String taskId = taskTestModel.getTaskId();
            Date realStartTime = taskTestModel.getRealStartTime();
            Date realEndTime = taskTestModel.getRealEndTime();
            // 温度
            BigDecimal temperature = taskTestModel.getTemperature();
            // 湿度
            BigDecimal humidity = taskTestModel.getHumidity();
            // 试验结论
            String testResult = taskTestModel.getTestResult();
            // 实施过程描述
            String processDesc = taskTestModel.getProcessDesc();

            if (Objects.isNull(testStartDate)) {
                testStartDate = realStartTime;
            } else if (Objects.nonNull(realStartTime)) {
                testStartDate = testStartDate.before(realStartTime) ? testStartDate : realStartTime;
            }

            if (Objects.isNull(testEndDate)) {
                testEndDate = realEndTime;
            } else if (Objects.nonNull(realEndTime)) {
                testEndDate = testEndDate.after(realEndTime) ? testEndDate : realEndTime;
            }

            minTemperature = ToolKit.minBigDecimal(2, temperature, minTemperature);
            maxTemperature = ToolKit.maxBigDecimal(2, temperature, maxTemperature);

            minHumidity = ToolKit.minBigDecimal(2, humidity, minHumidity);
            maxHumidity = ToolKit.maxBigDecimal(2, humidity, minHumidity);


            List<HfEnvTaskTestModel> taskTestList = taskTestVOListGroup.getOrDefault(taskId, new ArrayList<>());
            taskTestList.add(taskTestModel);
            taskTestVOListGroup.put(taskId, taskTestList);

            testResultList.add(testResult);

            processDescList.add(processDesc);
        }

        dataMap.put("testResult", String.join(",", testResultList));
        dataMap.put("processDesc", String.join(",", processDescList));

        Set<String> productNameSet = new HashSet<>();
        Set<String> pieceNoSet = new HashSet<>();
        Set<String> productAliasSet = new HashSet<>();
        Set<String> productCodeSet = new HashSet<>();
        int pieceNum = gkPieceList.size();
        for (HfEnvGkPiece gkPiece : gkPieceList) {
            String productName = gkPiece.getProductName();
            String pieceNo = gkPiece.getPieceNo();
            String productAlias = gkPiece.getProductAlias();
            String productCode = gkPiece.getProductCode();
            productNameSet.add(productName);
            pieceNoSet.add(pieceNo);
            productAliasSet.add(productAlias);
            productCodeSet.add(productCode);
        }
        dataMap.put("pieceNum", pieceNum);
        dataMap.put("productName", String.join(",", productNameSet));
        dataMap.put("pieceNo", String.join(",", pieceNoSet));
        dataMap.put("productCode", String.join(",", productCodeSet));
        dataMap.put("productAlias", String.join(",", productAliasSet));

        List<Map<String, Object>> taskMapList = new ArrayList<>();
        StringBuilder unitStandardName = new StringBuilder();
        ObjectMapper objectMapper = new ObjectMapper();
        for (HfEnvTask hfEnvTask : taskList) {
            String taskId = hfEnvTask.getId();
            Map taskMap = objectMapper.convertValue(hfEnvTask, Map.class);

            List<HfEnvTaskTestModel> taskTestList = taskTestVOListGroup.getOrDefault(taskId, new ArrayList<>());
            List<String> taskTestIdList = taskTestList.stream()
                    .map(HfEnvTaskTestModel::getId)
                    .collect(Collectors.toList());
            taskMap.put("testList", taskTestList);
            String unitName = hfEnvTask.getUnitName();
            String standardCode = hfEnvTask.getStandardCode();
            String standardName = hfEnvTask.getStandardName();
            unitStandardName.append(unitName).append("\t").append(standardName).append("\n");
            List<BaseOssFiles> testImageList = MinioUtil.listByRefIds(taskTestIdList
                    , TestConsts.TEST_REF_TYPE_IMAGE, true);
            List<BaseOssFiles> testCurveList = MinioUtil.listByRefIds(taskTestIdList
                    , TestConsts.TEST_REF_TYPE_CURVE, true);
            List<BaseOssFiles> testFileList = new ArrayList<>(testImageList);
            testFileList.addAll(testCurveList);
            taskMap.put("testFileList", testFileList);
            taskMapList.add(taskMap);
        }
        dataMap.put("taskList", taskMapList);
        dataMap.put("minTemperature", minTemperature);
        dataMap.put("maxTemperature", maxTemperature);
        dataMap.put("testEndDate", testEndDate);
        dataMap.put("testStartDate", testStartDate);
        dataMap.put("minHumidity", minHumidity);
        dataMap.put("maxHumidity", maxHumidity);
        dataMap.put("testList", taskTestModelList);

        QueryWrapper<BaseOssFiles> testOutlineQueryWrapper = new QueryWrapper<>();
        testOutlineQueryWrapper.lambda()
                .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_OUTLINE_REF_TYPE)
                .eq(BaseOssFiles::getRefId, gkEntrustId)
                .orderByAsc(BaseOssFiles::getRowSort);
        List<BaseOssFiles> testOutlineList = baseOssFilesService.list(testOutlineQueryWrapper);
        StringBuilder testOutlineBuilder = new StringBuilder();
        for (BaseOssFiles testOutlineFile : testOutlineList) {
            String fileName = testOutlineFile.getFileName();
            testOutlineBuilder.append(fileName).append("\n");
        }
        dataMap.put("testOutline", testOutlineBuilder.toString());
        return dataMap;
    }


}
